#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <unordered_map>
#include <algorithm>
#include "util.hpp"
#include "log.hpp"
#include <mutex>


namespace ns_index
{
    // 正排索引节点
    struct ForwardNode
    {
        std::string title;
        std::string content;
        std::string url;
        uint64_t doc_id;    
    };

    // 倒排索引节点
    struct InvertedNode
    {
        std::string word;
        uint64_t doc_id;    
        int weight;
    };

    class Index
    {
    public:
        typedef std::vector<InvertedNode> InvertedList; // 倒排拉链
    private:

        std::vector<ForwardNode> forward_index;    // 正排索引
        std::unordered_map<std::string, InvertedList> inverted_index;  // 倒排索引

        static Index* index_instance; 

        Index(){}
        Index(const Index& x) = delete;
        Index& operator=(const Index& x) = delete;
    public:   

        static Index* GetInstance()
        {
            static std::mutex mtx;
            if(nullptr == index_instance)
            {
                mtx.lock();
                if(nullptr == index_instance)
                {
                    index_instance = new Index();
                }
                mtx.unlock();
            }
            return index_instance;
        }

        bool BuildIndex(const std::string& input)
        {
            std::ifstream in(input, std::ios::in | std::ios::binary);
            if(in.is_open() == 0)
            {
                return false;
            }
            std::string line;
            while(std::getline(in, line))
            {                
                ForwardNode doc;

                // 构建正排节点
                if(BuildForwardIndex(line, doc) == 0)
                    return false;
                
                // 构建倒排拉链
                BuildInvertedIndex(doc);

                // 将节点加入正排索引中
                forward_index.push_back(std::move(doc));

                if(forward_index.size() % 50 == 0)
                {
                    // std::cout << "文档索引进度 " <<  forward_index.size() << std::endl;
                    std::string message = "文档索引进度 " + std::to_string(forward_index.size());
                    LOG(INFO, message.c_str());
                }
            }

            // std::cout << "文档索引完毕 "<< std::endl;
            LOG(INFO, "文档索引完毕 ");

            return true;
        }

        std::string GetDescription(const std::string& word, const std::string& content)
        {
            // 文章概要为 关键字前50字节 + 后 100 字节
            int pre_pos = 0;
            int end_pos =content.size() - 1;

            auto iter = std::search(content.begin(), content.end(), word.begin(), word.end(), 
                        [](int x, int y) -> bool
                        {
                            return std::tolower(x) == std::tolower(y);
                        });
            if(iter == content.end())
            {
                return "None";
            }
            
            int pos = iter - content.begin();
            if(pos - 50 > pre_pos)
                pre_pos = pos - 50;
            if(pos + word.size() + 100 < end_pos)
                end_pos = pos + word.size() + 100;
            
            return content.substr(pre_pos, end_pos - pre_pos);
        }

    private:
        // 构建正排索引
        bool BuildForwardIndex(const std::string& line, ForwardNode& doc)
        {
            std::vector<std::string> result;

            // 按 分隔符 进行切割
            ns_util::Split::TextSplit(line, result);
            if(result.size() != 3)
                return false;
            
            doc.title = result[0];
            doc.content = result[1];
            doc.url = result[2];
            doc.doc_id = forward_index.size();

            return true;
        }

        // 构建倒排索引
        void BuildInvertedIndex(const ForwardNode& doc)
        {
            // 根据处理好的文档建立倒排拉链
            InvertedList inverted_list;
            struct node
            {
                int title_cnt = 0;
                int content_cnt = 0;
            };
            std::unordered_map<std::string, node> mp_doc;

            // 分词 title
            std::vector<std::string> title_words;
            ns_util::Cut::CutText(doc.title, title_words);

            // 分词 content
            std::vector<std::string> content_words;
            ns_util::Cut::CutText(doc.content, content_words);


            for(auto word : title_words)
            {
                boost::to_lower(word);
                mp_doc[word].title_cnt++;
            }
            for(auto word : content_words)
            {
                boost::to_lower(word);
                mp_doc[word].content_cnt++;
            }
            for(auto& v : mp_doc)
            {
                InvertedNode newnode;

                newnode.word = v.first;
                newnode.weight = v.second.title_cnt * 10 + v.second.content_cnt;
                newnode.doc_id = doc.doc_id;

                inverted_index[v.first].push_back(std::move(newnode));
            }

        }

        // void BuildInvertedIndexAll()
        // {
        //     for(auto& doc : forward_index)
        //     {
        //         BuildInvertedIndex(doc);
        //     }
        // }

    
    public:
        // 给id 根据正排索引 得正排节点
        ForwardNode* GetForwardIndex(uint64_t id)
        {
            if(id >= forward_index.size())
            {
                std::cerr << "id error" << std::endl; 
                return nullptr;
            }

            return &forward_index[id];
        }
        
        // 给出关键词 根据倒排索引 得倒排拉链
        std::vector<InvertedNode>* GetInvertedList(std::string word)
        {
            boost::to_lower(word);
            if(inverted_index.count(word))
                return &inverted_index[word];
            
            return nullptr;
        }
        
    };

    Index* Index::index_instance = nullptr;
}